package ch.sv7.tool.dbmanager;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import ch.sv7.tool.dbmanager.db.dialect.CustomTypeConversion;
import ch.sv7.tool.dbmanager.db.dialect.Dialect;
import ch.sv7.tool.dbmanager.db.difference.AbstractTableDifference;
import ch.sv7.tool.dbmanager.db.difference.SchemaDifference;
import ch.sv7.tool.dbmanager.db.fixbuilder.FixBuilder;
import ch.sv7.tool.log.Logger;

/**
 * This is the central class allowing for custom configuration.
 *
 * @author svt
 *
 */
public class Context {
	
	private static final Logger log = Logger.getLogger(Context.class);

	public static final String FEATURE_PATH = "/ch/sv7/tool/dbmanager/db/feature/feature.properties";
	public static final String MAPPING_PATH = "/ch/sv7/tool/dbmanager/db/difference/diff2fix.properties";
	public static final String CONVERSIONS_PATH = "/ch/sv7/tool/dbmanager/db/conversion/conversions.properties";
	private Properties properties = new Properties();
	
	
	/**
	 * 
	 */
	public Context(Dialect dialect, String additionalProps) {
		super();
		try {
			loadDefaults();
		} catch (IOException e) {
			log.error(e.getMessage());
		}
		if (dialect != null) {
			properties.putAll(dialect.getContextProperties());
		}
		if (additionalProps != null) {
			String[] props = StringUtil.commaSeparatedToArray(additionalProps);
			for (int i=0; i<props.length; i++) {
				int pos = props[i].indexOf("=");
				if (pos > 0){
					String key = props[i].substring(0, pos).trim();
					String value = props[i].substring(pos + 1).trim();
					properties.setProperty(key, value);
				}
			}
		}
	}

	private void loadDefaults() throws IOException {
		readPropertiesFromPath(properties, FEATURE_PATH);
		readPropertiesFromPath(properties, MAPPING_PATH);
		readPropertiesFromPath(properties, CONVERSIONS_PATH);
	}
	
	public static void readPropertiesFromPath(Properties props, String path) throws IOException {
		InputStream is = null;
		try {
			is = Context.class.getResourceAsStream(path);
			props.load(is);
		} finally {
			if (is != null){
				is.close();
			}
		}	
		
	}
	
	public boolean doRecreateEmptyTable() {
		boolean result = "true".equalsIgnoreCase(
				properties.getProperty("Feature.reCreateEmptyTable", "false"));
		return result;
	}
	
	public boolean doDropExtraTable() {
		boolean result = "true".equalsIgnoreCase(
				properties.getProperty("Feature.dropExtraTable", "false"));
		return result;
	}
	
	/**
	 * Return the FixBuilder from the SchemaDifference, taking care of the empty table case
	 * @param difference
	 * @return
	 */
	public FixBuilder getFixBuilderClass(SchemaDifference difference) {
		String shortName = difference.getClass().getName();
		shortName = shortName.substring(shortName.lastIndexOf(".") + 1);
		
		String className = properties.getProperty("FixBuilder." + shortName);
		if (className != null && className.trim().length() > 0) {
			int commaPos = className.indexOf(",");
			if (commaPos >= 0){
				if (difference instanceof AbstractTableDifference){
					AbstractTableDifference tableDifference = (AbstractTableDifference)difference;
					if (doRecreateEmptyTable() 
							&& tableDifference.getActualTableSchema() != null 
							&& tableDifference.getActualTableSchema().isTableEmpty()) {
						className = className.substring(commaPos + 1);
					} else {
						className = className.substring(0, commaPos);
					}
				} 
			}
			try {
				return (FixBuilder)loadClassInstance(className);
			} catch (Exception e) {
				log.error("Unable to load class " + className + ", " + e.getMessage());
			}
		} else {
			log.info("No FixBuilder found for " + difference.getClass().getName());
		}
		return null;
	}
	
	
	private Object loadClassInstance(String className) {
		try {
			Class clazz = Class.forName(className);
			return clazz.newInstance();
		} catch (Exception e) {
			log.error("Unable to load class " + className + ", " + e.getMessage());
		}
		return null;
	}
	
	public CustomTypeConversion getConverter(String fromType, String toType) {
		String className = properties.getProperty("Conversion." + fromType + "-" + toType);
		if (className != null && className.trim().length() > 0) {
			return (CustomTypeConversion)loadClassInstance(className);
		}
		return null;
	}
}
